# -*- coding: utf-8 -*-
from httplib import *
import hashlib
from xml.dom.minidom import *
import re
import urllib
from PyKDE4.phonon import Phonon

# the following keys are specific to this plasmoid.
# api key: 47b90896668b2eca723eed02030883bc
# api secret: 8068511798a04e498bff0c045eebce0f

class LastFMTrack(Phonon.MediaSource):

	artist = None
	title = None
	art = None
	pixmap = None
	
	def __init__(self, url):

		Phonon.MediaSource.__init__(self, url)

class LastFMError(Exception):

	def __init__(self, value):

		self.value = value
	def __str__(self):

		return repr(self.value)

class LastFMConnection:

	apiKey = '47b90896668b2eca723eed02030883bc'
	apiSecret = '8068511798a04e498bff0c045eebce0f'
	sessionKey = None
	connection = None
	token = None

	def __init__ (self, debug = False):

		self.debug = debug

	def ensureConnection(self):

		if self.connection == None:
			self.connection = HTTPConnection('ws.audioscrobbler.com')

	def extractXMLValues(self, node, path, values = None):

		tags = path.split('/')
		tag = tags.pop(0)

		if values == None:
			values = list()

		if tag.endswith('*'):

			tag = tag[:-1]
			multiple = True
		else:

			multiple = False

		if len(tags) > 0:

			elements = node.getElementsByTagName(tag)
			if multiple:
			
				for element in elements:

					self.extractXMLValues(element, '/'.join(tags), values)
			else:

				self.extractXMLValues(elements[0], '/'.join(tags), values)
		else:

			elements = node.getElementsByTagName(tag)
			nodes = elements[0].childNodes

			value = None

			for node in nodes:

				if node.nodeType == node.TEXT_NODE:

					value = node.data
			values.append(value)

		return values

	def tuneNeighboursRadio(self, username):

		self.tuneRadio('lastfm://user/'+username+'/neighbours')

	def tuneRecommendationsRadio(self, username):

		self.tuneRadio('lastfm://user/'+username+'/recommended')

	def tuneLibraryRadio(self, username):

		self.tuneRadio('lastfm://user/'+username+'/library')

	def tuneLovedRadio(self, username):

		self.tuneRadio('lastfm://user/'+username+'/loved')

	def tuneSimilarArtistsRadio(self, artist):

		self.tuneRadio('lastfm://artist/'+artist+'/similarartists')

	def tuneTopFansRadio(self, artist):

		self.tuneRadio('lastfm://artist/'+artist+'/fans')

	def tuneTagRadio(self, tag):

		self.tuneRadio('lastfm://globaltags/'+tag)

	def httpGet(self, url):

		self.ensureConnection()
		try:
		
			self.connection.request('GET', url)
			response = self.connection.getresponse()
			body = response.read()
		except Exception as e:

			self.connection = None
			raise LastFMError('HTTP GET failed.')

		if self.debug:
			print response.status, response.reason
			print body

		return body

	def httpPost(self, url, headers, params):

		self.ensureConnection()
		try:

			self.connection.request('POST',url, urllib.urlencode(params), headers)
			response = self.connection.getresponse()
			body = response.read()
		except Exception as e:

			self.connection = None
			raise LastFMError('HTTP POST failed.')
	
		if self.debug:
			print response.status, response.reason
			print body

		return body

	def tuneRadio(self, station):
		
		url = '/2.0/'
		headers = {'Content-type':'application/x-www-form-urlencoded', 'Accept': 'text/plain'}
		params = {'method':'radio.tune', 'station':station, 'api_key':self.apiKey, 'sk':self.sessionKey}
		self.addApiSignature(params)
		
		if self.debug:
			print 'requested station:', station
			print 'urlencoded body:"'+urllib.urlencode(params)+'"'

		self.httpPost(url, headers, params)

	def requestToken(self):

		attributes = {'method':'auth.getToken', 'api_key':self.apiKey}
		self.addApiSignature(attributes)

		url = '/2.0/?'+urllib.urlencode(attributes)
		body = self.httpGet(url)
		
		dom = parseString(body)
		try:

			token = self.extractXMLValues(dom, 'lfm/token')[0]
		except IndexError:

			raise LastFMError('Could not get token.')

		self.token = token

	def getTracks(self):
		
		params = {'method':'radio.getPlaylist', 'api_key':self.apiKey, 'sk':self.sessionKey}
		self.addApiSignature(params)
		
		url = '/2.0/?'+urllib.urlencode(params)
		body = self.httpGet(url)

		dom = parseString(body)
		locations = self.extractXMLValues(dom, 'playlist/trackList/track*/location')
		titles = self.extractXMLValues(dom, 'playlist/trackList/track*/title')
		creators = self.extractXMLValues(dom, 'playlist/trackList/track*/creator')

		tracks = list()

		for location, title, creator in zip(locations, titles, creators):
			
			track = LastFMTrack(location)
			track.title = title
			track.artist = creator
			tracks.append(track)

		return tracks

	def getSessionKey(self):

		attributes = {'api_key':self.apiKey, 'method':'auth.getSession', 'token':self.token}
		self.addApiSignature(attributes)

		url = '/2.0/?'+urllib.urlencode(attributes)
		body = self.httpGet(url)
		
		dom = parseString(body)
		try:

			sessionKey = self.extractXMLValues(dom, 'lfm/session/key')[0]
		except IndexError:

			raise LastFMError('Could not get session key.')

		return sessionKey

	def addApiSignature(self, attributes):
		
		apiSig = ''
		keys = attributes.keys()
		keys.sort()
		for key in keys:
	
			apiSig += key+attributes[key]
		apiSig += self.apiSecret

		md5 = hashlib.md5()
		md5.update(apiSig)
		apiSigHex = md5.hexdigest()
		attributes.update({'api_sig':apiSigHex})

		if self.debug:
			print 'api signature:', apiSigHex

	def compileUrlQuery(self, attributes):

		apiSig = ''
		keys = attributes.keys()
		keys.sort()
		for key in keys:
	
			apiSig += key+attributes[key]
		apiSig += self.apiSecret

		md5 = hashlib.md5()
		md5.update(apiSig)
		apiSigHex = md5.hexdigest()

		attributes.update({'api_sig':apiSigHex})

		pairs = list()

		for (key, value) in attributes.items():
			pairs.append(key+'='+value)

		return '&'.join(pairs)

